home *** CD-ROM | disk | FTP | other *** search
/ Mac100% 1998 November / MAC100-1998-11.ISO.7z / MAC100-1998-11.ISO / オンラインソフト定点観測 / ユーティリティ / Mops 3.2.sea / Mops 3.2 / Mops source / PPC source / pnuc1 < prev    next >
Text File  |  1998-06-16  |  28KB  |  1,086 lines

  1. ¥ Objects, constants, values etc.
  2.  
  3. forward    INTERPRET        ¥ Not a vector any more - we never used that feature
  4. forward    REFILL
  5. forward    FREFILL
  6. forward    THROW
  7.  
  8. false        value        RAinMod        ¥ Set if a relocatable address is in a module
  9. false        value        echo?        ¥ Set if we're echoing during first stage load
  10.  
  11. false        value        err_info_valid?
  12.  
  13.  
  14.             variable    #TIB
  15.             variable    >IN
  16.  
  17. 0            value        LATEST
  18. 0            value        CURR-DEF
  19. 0            value        FENCE
  20. 0            value        SRC-START
  21. 0            value        SRC-LEN
  22. 0            value        SOURCE-ID
  23.  
  24. 0            value        ACTW
  25.  
  26. 0            value        OUT
  27. 0            value        #lines_read
  28. 0            value        STATE
  29. false        value        CSTATE
  30. 10            value        BASE
  31. -1            value        DPL
  32. 0            value        HLD
  33. false        value        CASE_IN_NAMES?
  34.  
  35. 0            value        throwHandler
  36. big#        value        DotStkLim
  37. -1            value        SLEEPTICKS
  38. 0            value        PROCESSOR
  39. true        constant    AppleEvents?    ¥ AppleEvents are always available on PPC
  40. true        constant    GestaltAvail?    ¥ Likewise for Gestalt
  41.  
  42. ¥ The following values are used internally by Mops.
  43.  
  44. 0            value        CD_gpr#
  45. 0            value        TO_gpr#
  46. 0            value        const_data_start
  47. 0            value        CD_GPR_loc
  48.  
  49. 0            value        savedRP
  50. 0            value        MMRgn
  51.  
  52. 0            value        meth_seg#
  53.  
  54. ¥ 0            value        seg#_accessed
  55. ¥ 0            value        class_seg#
  56.  
  57.  
  58. $ BFF12345 ,                        ¥ marker so we can easily recognize the 
  59.                                     ¥  execution buffer
  60.                                     
  61.             variable    exBuff        512 allot        ¥ the buffer
  62.             
  63. $ 98765432 ,                        ¥ marker so we can recognize the end
  64.  
  65. 0            value        exBuff_offs
  66. false        value        MRopen?
  67. false        value        initzed?
  68. 0            value        quitapp?
  69.  
  70. 0            value        frNxtDP
  71. 0            value        (err#)
  72. 0            value        loc#
  73. 0            value        #P
  74. 0            value        #PL
  75. 0            value        #FP
  76. 0            value        #FPL
  77. 0            value        tempObj_framesize    ¥ if nonzero, this is the size of the extra
  78.                                             ¥  part of the return stack frame, used for
  79.                                             ¥  temp objects.
  80. 0            value        releaseTemps_xt
  81. 0            value        fltflg
  82. 0            value        local?
  83. 0            value        method?
  84. 0            value        ^meth_link
  85. 0            value        selfref?
  86. 0            value        objclass
  87. 0            value        #1st
  88. 0            value        #last
  89. 0            value        heldMod
  90. 0            value        heldModStart
  91. ¥ 0            value        heldModBase
  92. 0            value        methindex
  93. false        value        sacomp?
  94. true        value        relocchk?
  95. false        value        inhibitmb?
  96. 0            value        sups2skip
  97. false        value        savingdic?
  98.  
  99.  
  100. BL            constant    BL
  101. 8            constant    #THREADS
  102. big#        constant    BIG#
  103. -300        constant    FILE-MARK
  104.  
  105. ¥ Some handler code values that we need to be able to access from
  106. ¥ above the nucleus:
  107.  
  108. classCode    constant    CLASSCODE
  109. objcode        constant    OBJCODE
  110. FvalCode    constant    FVALCODE
  111.  
  112. true        value        CURS?
  113. true        value        UCFLAG
  114. inlMk        constant    INLMK
  115.  
  116. 0            value        currBase
  117. 0            value        colAflg
  118.  
  119. ¥ 0            value        tempPtr
  120.             variable    tempVbl        16  allot
  121.  
  122.  
  123. ¥                    ==============================
  124. ¥                               SYSTEM VECTORS
  125. ¥                    ==============================
  126.  
  127. (*
  128.     ['] (emit)        -> emitvec
  129.     ['] (cr)        -> crvec
  130.     ['] (type)        -> typevec
  131.     ['] (spaces)    -> spvec
  132.     ['] (emit)        -> echovec
  133.     ['] (sf)        -> setfWind
  134. ¥    0                -> quitvec        ¥ mh May94 - quit doesn't get changed any more
  135.     ['] bye            -> byevec
  136. *)
  137.  
  138. ' null        sVect        HEADER
  139.  
  140. : rtnFalse    0  ;
  141.  
  142. ' null        sVect        LOGVEC
  143.  
  144. ¥ ' rtnFalse    sVect        UFIND
  145.  
  146.     dynamicVect            EXTRAFIND
  147.  
  148. ¥ ' null        sVect        NUMACCUMULATE
  149.  
  150.  
  151. ' null        sVect        PAUSE
  152. ' null        sVect        ?PAUSE
  153. ' null        sVect        GETSPACE
  154. ' null        sVect        RNGERR
  155. ' null        sVect        $ERR
  156. ' null        sVect        ARITHERR
  157. ' null        sVect        EXTRA_INITS
  158. ' null        sVect        ERRORVEC
  159. ' null        sVect        QUITVEC
  160. ' null        sVect        ABORTVEC
  161. ' null        sVect        SETFWIND
  162. ¥ ' null        sVect        DIE
  163. ¥ ' null        sVect        DFLT-DIE
  164. ¥ ' null        sVect        FREFILL
  165. ' null        sVect        MODLOAD
  166. ¥ ' null        sVect        TEIDLE
  167. ' null        sVect        COMPINLINE
  168. ¥ ' null        sVect        INTERPRET
  169.  
  170. ' null        sVect        OPENAPPVEC
  171. ' null        sVect        OPENDOCVEC
  172. ' null        sVect        PRINTDOCVEC
  173. ' null        sVect        QUITAPPVEC
  174. ' null        sVect        READ1DOCVEC
  175. ' null        vect        TEidle_vect
  176. ¥ ' null        vect        codeGen_vect
  177.  
  178.  
  179. ¥    ========= dummy words used for accessing locals (see zArgs) =========
  180.  
  181. $ BC0D    dummy_op    LOCPARM
  182. $ BC25    dummy_op    FLOCPARM
  183.  
  184.  
  185. ¥    ======== Dictionary header address conversion ========
  186.  
  187. : ?DP  ;
  188.  
  189.  
  190. ¥ TRAVERSE converts an addr pointing to one end of the name field
  191. ¥  to one pointing to the other.
  192.  
  193. : TRAVERSE { addr dirn ¥ cnt  -- addr' }
  194.     32 -> cnt
  195.     dirn 0>=
  196.     IF                        ¥ going up
  197.         addr c@  $ 1F and
  198.         4+ -4 and  1-  ++> addr
  199.     ELSE                    ¥ going down
  200.         BEGIN
  201.             1 --> addr
  202.             addr c@x 0< IF  addr EXIT drop THEN
  203.             1 --> cnt
  204.             cnt
  205.         NUNTIL
  206.     THEN
  207.     addr
  208. ;
  209.  
  210.  
  211. : N>LINK    4-  ;
  212. : L>NAME    4+  ;
  213. : NAME>        1 traverse  3+  ;
  214. : LINK>        L>name name> ;
  215.  
  216. ¥ >BODY ( xt -- dfa )  has to go to the data area for variables, values
  217. ¥  etc.  This isn't (and can't ever be) standard, since these kinds of
  218. ¥  words don't have an 'xt' under the standard.  But in Mops, you can
  219. ¥  tick them, and use >BODY on the result to get to the data.
  220.  
  221. : >BODY        2+ @abs  ;
  222. : >NAME        3-  -1 traverse  ;
  223. : >LINK        >name  n>link  ;
  224. : >HDLR        2-  ;
  225.  
  226.  
  227. ¥                    ==============================
  228. ¥                            STACK MANIPULATION
  229. ¥                    ==============================
  230.  
  231.  
  232. $ BD0F    $ 6200    special_op  DUP
  233. $ BD0F    $ 6300    special_op  2DUP
  234. $ BD0F    $ 6400    special_op  DROP
  235. $ BD0F    $ 6500    special_op  2DROP
  236. $ BD0F    $ 6600    special_op  SWAP
  237. $ BD0F    $ 6700    special_op  OVER
  238. $ BD0F    $ 6800    special_op  NIP
  239. $ BD0F    $ 6900    special_op  TUCK
  240. $ BD0F    $ 6A00    special_op  ROT
  241. $ BD0F    $ 6B00    special_op  DOWN
  242. $ BD0F    $ 6B00    special_op    -ROT        ¥ these are synonyms
  243. $ BD0F    $ 6C00    special_op    2SWAP
  244.  
  245. ¥ FP stack ops:
  246.  
  247. $ BD0F    $ 7200    special_op  FDUP
  248. $ BD0F    $ 7300    special_op  F2DUP
  249. $ BD0F    $ 7400    special_op  FDROP
  250. $ BD0F    $ 7500    special_op  F2DROP
  251. $ BD0F    $ 7600    special_op  FSWAP
  252. $ BD0F    $ 7700    special_op  FOVER
  253. $ BD0F    $ 7800    special_op  FNIP
  254. $ BD0F    $ 7900    special_op  FTUCK
  255. $ BD0F    $ 7A00    special_op  FROT
  256. $ BD0F    $ 7B00    special_op  FDOWN
  257. $ BD0F    $ 7C00    special_op    F2SWAP
  258.  
  259.  
  260. ¥ I use the following in inline code sequences here in the nucleus, before
  261. ¥  locals are avaliable.  And they're also handy in inlines.
  262.  
  263. $ BD0F    $ 6D00    special_op    2PICK
  264. $ BD0F    $ 6E00    special_op    3PICK
  265. $ BD0F    $ 6F00    special_op    3ROLL
  266.  
  267.  
  268. :ppc_code PICK
  269.     r4    0            cmpi,        ¥ is it 0 pick?
  270. eq if,
  271.     r4    r3 r3        or,            ¥ yes - copy TOS
  272. else,
  273.     r5    r4 2 0 29    rlwinm,        ¥ no - mult index by 4
  274.     r5    r5 -4        addi,        ¥  and subtract 4 to get SP offset
  275.     r4    r18 r5        lwzx,        ¥ grab the cell
  276. then,
  277.  
  278.                     blr,        ¥ and return.
  279. ;ppc_code
  280.  
  281.  
  282. ¥                =============================
  283. ¥                     SIMPLE ARITHMETIC
  284. ¥                =============================
  285.  
  286.  
  287. $ BD06    otAdd    special_op  +
  288. $ BD06    otSub    special_op  -
  289. $ BD06    otMul    special_op    *
  290. $ BD06    otMul    special_op    *W        ¥ don't need this as a separate op on PPC
  291. $ BD06    otMulh    special_op    *HI        ¥ will normally only be used internally
  292. $ BD06    otUMulh    special_op    *UHI    ¥ ditto
  293. $ BD06    otDiv    special_op    /
  294. $ BD06    otUDiv    special_op    U/
  295.  
  296. : M*   ( n1 n2 -- d )    inline{ 2dup * down *hi}  ;
  297. : UM*  ( u1 u2 -- ud )    inline{ 2dup * down *uhi} ;
  298.  
  299. ¥ we need um* - the standard sez so!!
  300.  
  301. ¥ Special arith ops to get us specific instructions, mainly for use
  302. ¥  in inline sequences.  We leave it as an exercise for the reader 
  303. ¥  to work out what the instructions are.
  304.  
  305. $ BD06    otAddc        special_op    __addc
  306. $ BD06    otAdde        special_op    __adde
  307. $ BD06    otAddze        special_op    __addze
  308. $ BD06    otSubfc        special_op    __subfc
  309. $ BD06    otSubfe        special_op    __subfe
  310. $ BD06    otSubfze    special_op    __subfze
  311.  
  312.  
  313. ¥ NEGATE and DNEGATE.  The latter can be done with the special ops we just
  314. ¥  defined.
  315.  
  316. $ BD06    otNEG    special_op  NEGATE
  317.  
  318. : DNEGATE    inline{ swap 0 __subfc swap __subfze}  ;
  319.  
  320. ¥ We need D+ in number input, so we might as well put D- here as well.
  321. ¥ These sequences do the job in 2 or 3 instructions.
  322.  
  323. : D+  ( d1 d2 -- d3 )
  324.      inline{ swap 3roll __addc down __adde}  ;
  325.  
  326.  
  327. : D-  ( d1 d2 -- d3 )
  328.     inline{ swap 3roll swap __subfc down __subfe}  ;
  329.  
  330.  
  331. ¥ FP:
  332.  
  333. $ BD06    otFADD    special_op    F+
  334. $ BD06    otFSUB    special_op    F-
  335. $ BD06    otFMUL    special_op    F*
  336. $ BD06    otFDIV    special_op    F/
  337.  
  338. $ BD06    $ 54    special_op    FABS
  339. $ BD06    $ 55    special_op    FNEGATE
  340.  
  341.  
  342. ¥ Shifts:
  343.  
  344. $ BD30    $ 2A00    special_op  <<
  345. $ BD30    $ 2A00    special_op  LSHIFT
  346. $ BD30    $ 2A01    special_op  >>
  347. $ BD30    $ 2A01    special_op  RSHIFT
  348. $ BD30    $ 2A03    special_op  A>>
  349.  
  350.  
  351. ¥ the following inline definitions use some ops like > which we haven't
  352. ¥  defined in the nucleus image yet.  But since inlines use EVALUATE,
  353. ¥  as long as the ops are defined somewhere in the nucleus there should
  354. ¥  be no problem, since we precompile the nucleus.
  355.  
  356. : 2*    inline{ dup +}  ;
  357. : 4*    inline{ 2 <<}    ;
  358.  
  359. : 2/    inline{ 1 a>>}  ;
  360. : 4/    inline{ 2 a>>}    ;
  361.  
  362. : UNDER+    ¥ ( a b c -- a+c b )
  363.         inline{ rot + swap}  ;
  364.  
  365. : MAX    inline{ 2dup >= dup not rot and down and or}  ;
  366. : MIN    inline{ 2dup < dup not rot and down and or}  ;
  367.                 ¥ we use >= instead of > for MAX, since this gives one
  368.                 ¥  less instruction in the case 0 MAX.  But for MIN,
  369.                 ¥  using < gives TWO less instructions than <= (just 2)
  370.  
  371. : UMAX    inline{ 2dup u> dup not rot and down and or}  ;
  372. : UMIN    inline{ 2dup u< dup not rot and down and or}  ;
  373.                 ¥ Here u>/u< gives one less instruction than
  374.                 ¥  u>=/u<=.
  375.  
  376. : ABS    inline{ dup 31 a>> tuck + xor}  ;    ¥ yep, it works!!
  377.  
  378. ¥ +- ( n1 n2 -- n3 )  negates n1 if n2 is negative.  I like this name
  379. ¥  better than ?negate, since n2 isn't a flag.  Note that ABS is
  380. ¥  equivalent to DUP +-.
  381.  
  382. : +-    inline{ 31 a>> tuck + xor}  ;
  383.  
  384.  
  385. : #ALIGN4    inline{ 3+ -4 and}  ;    ¥ other alignment words are in pnuc3,
  386.                                     ¥  but we need this one earlier.
  387.  
  388. : EXTEND    inline{ 16 << 16 a>>}  ;
  389. : S>D        inline{ dup 31 a>>}  ;
  390.  
  391.  
  392.  
  393. ¥                =============================
  394. ¥                      LOGICAL OPERATIONS
  395. ¥                =============================
  396.  
  397.  
  398. ¥ NOT and INVERT are synonyms.
  399.  
  400. $ BD06    otNOT    special_op  NOT
  401. $ BD06    otNOT    special_op  INVERT
  402.  
  403. $ BD06    otAND    special_op  AND
  404. $ BD06    otOR    special_op  OR
  405. $ BD06    otXOR    special_op  XOR
  406.  
  407.  
  408. ¥ Logical operations directly on a memory byte.  We define these as inlines,
  409. ¥  since the'll only generate a few instructions.
  410.  
  411. : CSET      ¥ ( c addr -- )  ORs c into the byte at addr.
  412.  
  413.     inline{ dup c@ rot or swap c!}  ;
  414.  
  415. : CRESET    ¥ ( c addr -- )  clears bits in byte at addr, corresponding
  416.             ¥ to the bits SET in c.    
  417.             
  418.     inline{ dup c@ rot not and swap c!}  ;
  419.  
  420. : CTOGGLE    ¥ ( c addr -- )  Exclusive-ORs c into the byte at addr.
  421.  
  422.     inline{ dup c@ rot xor swap c!}  ;
  423.  
  424.  
  425. : CREPLACE    ¥ ( c mask addr -- )
  426.             ¥ Replaces bits in the addressed byte with the corresponding
  427.             ¥ bits from c, in those positions where the mask has ones.
  428.  
  429.     inline{ 2dup c@ swap not and 2swap and or swap c!}  ;
  430.  
  431. (*
  432. : CREPLACE  { c mask addr -- }
  433.     addr c@  mask not and  c mask and  or  addr c!  ;
  434. *)
  435.  
  436. ¥ Logical operations on a memory bit - now omitted.  Almost unused.
  437.  
  438.  
  439. ¥            ===========================
  440. ¥                    COMPARISONS
  441. ¥            ===========================
  442.  
  443.  
  444. $ BD10    $ 2607    special_op  =
  445. $ BD10    $ 2606    special_op  <>
  446. $ BD10    $ 260C    special_op  >=
  447. $ BD10    $ 260D    special_op  <
  448. $ BD10    $ 260F    special_op  <=
  449. $ BD10    $ 260E    special_op  >
  450.  
  451. $ BD10    $ 2605    special_op  U<
  452. $ BD10    $ 2603    special_op  U<=
  453. $ BD10    $ 2602    special_op  U>
  454. $ BD10    $ 2604    special_op  U>=
  455.  
  456. $ BD10    $ 2617    special_op  0=
  457. $ BD10    $ 2616    special_op  0<>
  458. $ BD10    $ 261C    special_op  0>=
  459. $ BD10    $ 261D    special_op  0<
  460. $ BD10    $ 261F    special_op  0<=
  461. $ BD10    $ 261E    special_op  0>
  462.  
  463. $ BD2A    cmpEQ    special_op  F=
  464. $ BD2A    cmpNE    special_op  F<>
  465. $ BD2A    cmpGE    special_op  F>=
  466. $ BD2A    cmpLT    special_op  F<
  467. $ BD2A    cmpLE    special_op  F<=
  468. $ BD2A    cmpGT    special_op  F>
  469.  
  470. ¥ FP:
  471.  
  472. $ BD2A    cmpZEQ    special_op  F0=
  473. $ BD2A    cmpZNE    special_op  F0<>
  474. $ BD2A    cmpZGE    special_op  F0>=
  475. $ BD2A    cmpZLT    special_op  F0<
  476. $ BD2A    cmpZLE    special_op  F0<=
  477. $ BD2A    cmpZGT    special_op  F0>
  478.  
  479.  
  480. : WITHIN?    ¥ ( n lo hi -- n b )  Returns true if  lo <= n <= hi.
  481.  
  482.             ¥ We define it inline which involves a lot of stack juggling,
  483.             ¥ but all that gets taken out at compile time, so the compiled
  484.             ¥ code is actually optimum.
  485.  
  486.     inline{ rot tuck >= down tuck <= rot and}  ;
  487.  
  488. (* that surely needs an explanation:
  489.     rot                    ( lo hi n )
  490.     tuck                ( lo n hi n )
  491.     >= down                ( b lo n )
  492.     tuck                ( b n lo n )
  493.     <=                    ( b n b' )
  494.     rot and
  495. *)
  496.  
  497. : UWITHIN?    ¥ ( u lo hi -- u b )  An unsigned version of WITHIN?
  498.     inline{ rot tuck u>= down tuck u<= rot and}  ;
  499.  
  500.  
  501. ¥            ===========================
  502. ¥                FETCHES AND STORES
  503. ¥            ===========================
  504.  
  505.  
  506. $ 6102    0    fetch_op    @
  507. $ 6102    0    fetch_op    >PTR        ¥ In our system, this is an alias for @.
  508.  
  509. $ 6101    0    fetch_op    W@
  510. $ 6101    1    fetch_op    W@X
  511. $ 6100    0    fetch_op    C@
  512. $ 6100    1    fetch_op    C@X
  513.  
  514. $ BD32        simple_op    F@
  515. $ BD33        simple_op    F!
  516. $ BD42        simple_op    SF@
  517. $ BD43        simple_op    SF!
  518.  
  519. $ BD08    $ 6002    special_op    !
  520. $ BD08    $ 2102    special_op    +!
  521. $ BD08    $ 2202    special_op    -!
  522. $ BD08    $ 6001    special_op    W!
  523. $ BD08    $ 2101    special_op    W+!
  524. $ BD08    $ 2201    special_op    W-!
  525. $ BD08    $ 6000    special_op    C!
  526.  
  527.  
  528.  
  529. ¥            ============================================
  530. ¥                DO LOOPS and RETURN STACK OPERATIONS
  531. ¥            ============================================
  532.  
  533. (* Note:  >R, R> and R@ are defined already (at the start of Setup, since
  534.  I needed >R so it was logical to put them all there).
  535.  
  536.  We keep the loop index I in a reg, but the return stack is entirely
  537.  in memory, except that in leaf words we don't save/restore the link
  538.  register.  This means that I can be used in words called from within
  539.  DO loops.  In fact I can be used as another local variable.  But this
  540.  is non-standard, so not a good idea.  But it's useful for testing.
  541.  
  542.  During DO loops, the info for any containing DO loop is saved on the
  543.  return stack in the order I (on top), limit, count register.  Thus
  544.  J is at offset zero off r17 (rtn stk ptr), and K is at offset 12.
  545. *)
  546.  
  547. I_reg        gpr  I
  548.  
  549. : J        inline{ [ 17 0 (litaddr) ] @}  ;    ¥ r17 is return stk pointer
  550.  
  551. : K        inline{ [ 17 8 (litaddr) ] @}  ;
  552.  
  553.  
  554. ¥                    =========================
  555. ¥                        OBJECT ADDRESSING
  556. ¥                    =========================
  557.  
  558. (*
  559.   ^BASE and SELF give the base address of the current object.  There are two
  560.   words because "base address of the current object" can have two meanings, thanks
  561.   to multiple inheritance.  ^BASE give what we might call the local base - the
  562.   base address of the current object considered as an object of the class in which
  563.   the ^BASE appears or from which it is called.  In other words, this is the
  564.   address of the first ivar of the class in which the current method is declared.
  565.   Note that all ivars of this class will be at fixed offsets from ^BASE.
  566.   However with multiple inheritance, these ivars might be preceded by ivars of
  567.   a different (inherited) class.  SELF simply the base address of the current
  568.   (dynamic) object, that is, the address of the first ivar (regardless of which
  569.   class it's inherited from).  SELF and ^BASE might give identical results, but
  570.    if they differ, SELF must be lower.
  571.  
  572.   Compiled code in methods needs to access ivars using ^BASE, since the offsets
  573.   are fixed.  The offset from SELF of a given ivar might be different in different
  574.   objects.  For this reason we keep ^BASE in a machine register, but compute SELF.
  575.  
  576. *)
  577.  
  578. ¥ obj_base_reg    reg    ^BASE
  579.  
  580. : SELF  ( -- addr )
  581.             ¥ Returns the "real" base addr of the current object.
  582.  
  583.     (^base) 4- dup w@x +        ¥ ^class addr
  584.     8 +  ;                        ¥ forward to beginning of obj data
  585.  
  586.  
  587. ¥                    =========================
  588. ¥                        SEGMENT HANDLING
  589. ¥                    =========================
  590.  
  591. (*
  592.     A segment table (ST) entry is 8 bytes long:
  593.     
  594.     byte  0            flags
  595.     bytes 1-3        length of segment
  596.     bytes 4-7        base addr
  597.  
  598.     A free segment is marked by bytes 0-3 being all zero.  Currently
  599.     we don't have such a thing as a zero-length segment, though if
  600.     this ever became useful we could define a flag bit to mean a
  601.     segment isn't free, so that bytes 0-3 being all zero would still
  602.     mean the seg is free.
  603.  
  604.     Note that 2^^24 is more than adequate for a maximum length, so
  605.     there's no problem with using the hi byte for flags.
  606.     
  607.     The maximum number of available ST slots is max_segs.  We number
  608.     segments from 8 up, corresponding to the hi byte of relocatable
  609.     addresses.  Thus the highest legal seg# is max_segs + 7.
  610.     (Offsetting the seg# in this way makes handling reloc addrs 
  611.     slightly easier, and also means that zero is illegal as a reloc
  612.     addr - probably a good idea.)
  613. *)
  614.  
  615. : get_free_seg_pair  { ¥ ^entry -- ^entry n }
  616.     max_segs 2
  617.     DO    i  8 *  segTable +  -> ^entry
  618.         ^entry @  ^entry 8 + @  or
  619.         NIF                        ¥ found the first free even-odd pair
  620.             1 ^entry !            ¥ give them a dummy length of 1 so we can see
  621.             1 ^entry 8 + !        ¥  they're not free
  622.             ^entry  i 8 +  UNLOOP  EXIT
  623.         THEN
  624.     2 +LOOP
  625.     208 die                    ¥ table full!  Help!!
  626. ;
  627.  
  628. : segTable_entry        ¥ ( seg# -- ^entry )
  629.     8 - 
  630.     0 max_segs  within?  NIF 207 die  THEN
  631.     8 *  segTable +
  632. ;
  633.  
  634. : make_seg_absent        ¥ ( seg# -- )
  635.     segTable_entry 4+
  636.     nilP swap !            ¥ nilP means it's absent.  Note we leave the 
  637.                         ¥  length alone, since the seg is still assigned
  638.                         ¥  to somebody.
  639. ;
  640.  
  641. : free_seg                ¥ ( seg# -- )
  642.     segTable_entry
  643.     0  over !
  644.     nilP swap 4+ !
  645. ;
  646.  
  647. 0 value cctest
  648.  
  649. : dotest  true -> cctest  ;
  650.  
  651. : addr>S&D  { addr ¥ ^entry BA len --  seg# displ }
  652.  
  653. ¥ compMod $ 10000000 u> if dbgr then
  654. ¥ addr $ 1000 u< if dbgr then
  655.  
  656.     compMod 0<> comp_seg# and
  657.     IF
  658.         comp_seg# 8 -  8 *  segTable +  -> ^entry
  659.         ^entry @ $ 00ffffff and  -> len
  660.         ^entry 4+ @ -> BA
  661.         addr
  662.         modcode_comp_start   BA len +
  663.         uwithin?
  664.         IF                ¥ found!
  665.             modcode_comp_start -  comp_seg#  swap  EXIT
  666.         THEN
  667.         ^entry 8 + @ $ 00ffffff and  -> len  ^entry 12 + @  -> BA
  668.     ( addr )
  669.         moddata_comp_start  BA len +
  670.         uwithin?
  671.         IF        moddata_comp_start -  comp_seg# 1+ swap  EXIT
  672.         THEN    drop
  673.     THEN
  674.  
  675.     max_segs 0
  676.     DO    i  8 *  segTable +  -> ^entry
  677.         ^entry @ $ 00ffffff and  -> len
  678.         len
  679.         IF                        ¥ something there
  680.             ^entry 4+ @ -> BA
  681.             BA nilP <>
  682.             IF                    ¥ seg is present
  683.                 addr
  684.                 BA dup len +  uwithin?
  685.                 IF                ¥ found!  addr is within this segment
  686.                         BA -
  687.                         i 8 +  swap UNLOOP  EXIT
  688.                 ELSE    drop
  689.                 THEN
  690.             THEN
  691.         THEN
  692.     LOOP
  693.     0  0        ¥ search failed - return two zeros
  694. ;
  695.  
  696.  
  697.  
  698. ¥                    =============================
  699. ¥                    MISCELLANEOUS LOW-LEVEL WORDS
  700. ¥                    =============================
  701.  
  702.  
  703. ¥ SP@ should really only be used for stack dumping.  Therefore the
  704. ¥ main job is to ensure the memory part of the stack is updated to
  705. ¥ what's in the regs.
  706.  
  707. :ppc_code SP@
  708.  
  709. $ 0100 codeHere 2- w!    ¥ change flags to specify 1 result in regs.  This
  710.                         ¥  simplifies things, since this 1 result is just
  711.                         ¥  the updated data stack pointer.
  712.  
  713.     r3        -4    rSP        stw,
  714.     r4        -8    rSP        stwu,
  715.     r3        rSP            mr,
  716.                         blr,
  717. ;ppc_code
  718.  
  719.  
  720. : SP!    -> SP  ;
  721.  
  722. RP_reg    gpr  RP@        ¥ synonym for RP in Mops
  723.  
  724. : RP!    0 -> exBuff_offs  -1 -> (^base)
  725.         -> RP  ;
  726.         
  727. : FSP!    -> FSP  ;
  728.  
  729.  
  730. : BOUNDS    inline{ over + swap}  ;
  731.  
  732. : HERE        inline{ dp}  ;
  733.  
  734. : ALLOT        inline{ ++> dp}  ;
  735.  
  736. : ROOM  ( -- n )
  737.     code_limit CDP -  ;
  738.  
  739. : ROOM2  ( -- code-room data-room )
  740.     code_limit CDP -  data_limit DP -  ;
  741.  
  742.     
  743. : HEADROOM  ( -- n )    ¥ On the 68k, returns the distance from DP to the top of
  744.                         ¥  the A4 addressing range.  Here on the PPC we make it
  745.                         ¥  the distance from CDP to the top of the mainCode addressing
  746.                         ¥  range - that's probably somewhat useful, though the
  747.                         ¥  distance from DP to the top of the mainData addressing
  748.                         ¥  range would be useful as well.
  749.     mainCode half_displ_range +  CDP -  ;
  750.  
  751.  
  752. : UNUSED    inline{ room}  ;
  753.  
  754. : COUNT        inline{ dup 1+ swap c@}  ;
  755.  
  756. : LENGTH    inline{ dup 2+ swap w@}  ;
  757.  
  758. : DEPTH
  759.     SP0 SP -  4/  2+  ;            ¥ we have 2 cells in regs on entry
  760.     
  761. : FDEPTH
  762.     FSP0 FSP -  3 a>>  2+  ;    ¥ ditto
  763.  
  764.  
  765. : DIGIT  { char #base -- b }
  766.     false
  767.     char  & z  u>    ?EXIT                    ¥ if above LC letters, fail
  768.     char  & a  u>= IF $ DF and> char THEN    ¥ LC letter -> UC
  769.     $ 30  --> char                            ¥ '0'-'9' -> 0-9
  770.     char 0<            ?EXIT                    ¥ if not a digit, fail
  771.     char 10 >=
  772.     IF    7 --> char                            ¥ A-Z -> 10-35
  773.         char 10 <    ?EXIT                    ¥ but if not a letter, fail
  774.     THEN
  775.     char #base >=    ?EXIT                    ¥ if char now > base, fail
  776.     drop  char true                            ¥ if we got here, success!
  777. ;
  778.  
  779.  
  780. : DECIMAL    10 -> base  ;
  781. : HEX        16 -> base  ;
  782.  
  783.  
  784. (* HASH produces a 32-bit hash value.  We always set the top bit
  785.   (so that a hashed value is never zero, and is always distinguishable
  786.   from a relocatable address, which is always "positive").
  787.  
  788.   This means that we effectively have 2**31 hash possibilities.  This is
  789.   large enough that hash collisions should hardly ever occur.
  790.   If a 16-bit hash value is required, as in Neon, use wHash.
  791.   
  792.   We use assembly for the inner loop, mainly because we don't yet have
  793.   a good way of specifying a rotate in high-level.  But it's interesting
  794.   that I hardly ever have to resort to assembly for anything any more...
  795. *)
  796.  
  797. :ppc_code (hash)    ¥ ( addr -- hash )
  798.  
  799.     r5        $ 12345678    lli,
  800.     r5        8            srwi,
  801.  
  802.     r0        0    r4        lbz,
  803.     r0        $ 7F        andi.,
  804.     r0                    mtctr,
  805.     rX        r4    1        addi,
  806.     r4        r0    0        addi,
  807. begin,
  808.     r4        r4 7 0 31    rlwinm,
  809.     r0        0    rX        lbz,
  810.     rX        1            addi,
  811.     r4        r0            xor,
  812. dnz until,
  813.                         blr,
  814.  
  815. ;ppc_code
  816.  
  817.  
  818. : HASH
  819.     (hash)
  820.     dup 0> IF  not  THEN  ;
  821.  
  822. : WHASH
  823.     (hash)
  824.     dup $ FFFF and
  825.     swap 16 >> xor  ;
  826.  
  827.  
  828. : <^ELEM>  { index ¥ addr -- addr index }
  829.             ¥ Returns addr of indexed element in current object.
  830.  
  831. ¥    (^base) dup 4- w@x +        ¥ ^class addr
  832. ¥    dup 6 + w@x +  -> addr        ¥ indexed base addr
  833. ¥    index  addr 4- @ u>  ?trap    ¥ trap if out of range - note we store
  834.                                     ¥  limit-1 in the object, so equal is OK.
  835.  
  836.     (^base) 2- dup w@x + -> addr    ¥ indexed area base addr
  837.     index  addr 4- @ u>  ?trap        ¥ trap if out of range - note we store
  838.                                     ¥  limit-1 in the object, so equal is OK.
  839.     addr index  ;
  840.  
  841.  
  842. : (^ELEM)
  843.     <^elem>  over 6 - w@  * +  ;    ¥ compiled by ^ELEM if we're not
  844.                                     ¥  expanding an inline defn - see
  845.                                     ¥  qClass.
  846.  
  847. : ^ELEM1    <^elem>  +  ;
  848.  
  849. : ^ELEM2    <^elem>  dup + +  ;
  850. : ^ELEM4    <^elem>  4* +  ;
  851.  
  852.  
  853. : IDXBASE  { ¥ addr -- addr }
  854.             ¥ Returns start addr of indexed area in current object.
  855.  
  856. ¥    (^base) dup 4- w@x +        ¥ ^class addr
  857. ¥    dup 2- w@x +  -> addr        ¥ indexed base addr
  858.  
  859.     (^base) 2- dup w@x + -> addr    ¥ indexed area base addr
  860.     addr 4- @ 0<  ?trap                ¥ trap if not indexed
  861.     addr ;
  862.  
  863. : LIMIT
  864.     idxbase 4- @ 1+  ;        ¥ we store limit-1 in the object
  865.  
  866.  
  867.  
  868. (*    Extra multiplication and division words.
  869.     On the 68k, we dispensed with all double length (64-bit) arithmetic 
  870.     in the nucleus, since the hardware didn't provide it.  We used a kludged
  871.     version of I/O words such as #, in which we just ignored the high
  872.     word.  We required loading of an extra file (longMath) if the real 
  873.     64-bit words were needed.  However here we do provide a few 64-bit 
  874.     words since 32*32->64 is easy, and the Compiler Writers' Guide has
  875.     given us a 64/64->64 division routine.  This means that we don't have
  876.     to kludge # et al, and don't need a PowerPC version of longMath.
  877. *)
  878.  
  879. : /MOD    inline{ 2dup / -> rX rX * - rX}  ;
  880.                     ¥ tried assembly, but the code compiled by this was
  881.                     ¥  identical, except for reg numbers  :-)
  882.  
  883. : U/MOD    inline{ 2dup u/ -> rX rX * - rX}  ;
  884.  
  885. : MOD    inline{ /mod drop}  ;
  886.  
  887.  
  888.  
  889. (*    64-bit division on 32-bit PowerPC implementations isn't easy, since
  890.     they took away the MQ register, and left us with only 32/32->32
  891.     instructions.
  892.     
  893.     But fortunately the Compiler Writer's Guide tells us how to do
  894.     64/64->64, so here we go...
  895. *)
  896.  
  897.  
  898. :ppc_code UD/MOD  ( ud_dvd ud_dsr -- ud_rem ud_quot )
  899.  
  900. (*    On entry: divisor = r4:r3, dividend in 0(rSP):4(rSP), and
  901.     we move it to r6:r5.
  902.     We use tmp = r8:r7.  r0 and r10 are scratch.
  903.     
  904.     Note the dividend is only 64 bits, instead of the 128 that 
  905.     would normally go with a 64 bit divisor.  We assume the high
  906.     64 bits are zero.  This means that no divisor/dividend 
  907.     combinations can overflow, unless the divisor is zero.
  908.  
  909.     Note also we put the most significant cell second in the
  910.     registers, because that's the way the regs get passed in to us 
  911.     and the way we need to return them, and it's less confusing 
  912.     to be consistent all the way through - once we get over
  913.     the confusion of having the registers this way around.
  914. *)
  915.  
  916. ¥ first we check for zero divisor
  917.  
  918.     r0        r3    r4        or.,
  919. ne if,
  920.  
  921.     r6        0    rSP        lwz,        ¥ get dividend to r6:r5
  922.     r5        4    rSP        lwz,
  923.  
  924. ¥ first we count the leading zeros in the dividend -> r0
  925.  
  926.     r6        0            cmpi,        ¥ dvd(hi) = 0?
  927.     r0        r6            cntlzw,        ¥ r0 = LZ in dvd(hi)
  928.     r9        r5            cntlzw,        ¥ r9 = LZ in dvd(lo)
  929. eq if,                                ¥ if dvd(hi) = 0
  930.     r0        r9    32        addi,        ¥   LZ = LZ(lo) + 32
  931. then,
  932.  
  933. ¥ now we count the leading zeros in the divisor -> r9
  934.  
  935.     r4        0            cmpi,        ¥ dsr(hi) = 0?
  936.     r9        r4            cntlzw,        ¥ r9 = LZ in dsr(hi)
  937.     r10        r3            cntlzw,        ¥ r10 = LZ in dsr(lo)
  938. eq if,                                ¥ if dsr(hi) = 0
  939.     r9        r10    32        addi,        ¥   LZ = LZ(lo) + 32
  940. then,
  941.  
  942. ¥ now we work out the shift amounts to minimize the number of
  943. ¥  iterations.
  944.  
  945.     r0        r9            cmp,        ¥ compare dvd LZ to dsr LZ
  946.     r10        r0    64        subfic,        ¥ r10 = dividend sig digits (SD)
  947. le if,                                ¥ if divisor > dividend we keep going,
  948.                                     ¥  otherwise we set quotient to 0
  949.     r9        r9    1        addi,
  950.     r9        r9    64        subfic,        ¥ r9 = divisor SD
  951.     r0        r0    r9        add,        ¥ r0 =  dvd LZ + dsr SD, i.e. left shift
  952.                                     ¥  of dvd for initial tmp
  953.     r9        r9    r10        subf,        ¥ r9 = dvd SD - dsr SD i.e. right shift
  954.                                     ¥  of dividend for initial temp
  955.     r9                    mtctr,        ¥ ..which is also the number of iterations.
  956.  
  957. ¥ now we set up r8:r7:r6:r5 as the classic division register whose length
  958. ¥  is the sum of the quotient and remainder lengths - in our case, 128 bits.
  959. ¥  First, the hi-order part (r8:r7) is the dividend, right shifted by r9
  960. ¥  (the number of iterations).
  961.  
  962.     r9        32            cmpi,        ¥ r9 ? 32
  963.     r8        r9    -32        addi,
  964. ge if,                                ¥ r9 >= 32:
  965.     r7        r6    r8        srw,        ¥    lo word = dvd(hi) >> (r9-32)
  966.     r8        0            li,            ¥   hi word = 0
  967. else,                                ¥ r9 < 32:
  968.     r7        r5    r9        srw,        ¥    lo word = dvd(lo) >> r9
  969.     r8        r9    32        subfic,
  970.     r8        r6    r8        slw,        ¥    r8 = dvd(hi) << (32-r9)
  971.     r7        r7    r8        or,            ¥     OR that into lo word
  972.     r8        r6    r9        srw,        ¥    hi word = dvd(hi) >> r9
  973. then,
  974.  
  975. ¥ Now the lo-order part of the division register (r6:r5) is the
  976. ¥  dividend left shifted by r0.
  977.  
  978.     r0        32            cmpi,        ¥ r0 ? 32
  979.     r9        r0    -32        addic,
  980. ge if,                                ¥ r0 >= 32:
  981.     r6        r5    r9        slw,        ¥   hi word = dvd(lo) << (r0-32)
  982.     r5        0            li,            ¥    lo word = 0
  983. else,                                ¥ r0 < 32:
  984.     r6        r6    r0        slw,        ¥    hi word = dvd(hi) << r0
  985.     r9        r0    32        subfic,
  986.     r9        r5    r9        srw,        ¥    r9 = dvd(lo) >> (r0-32)
  987.     r6        r6    r9        or,            ¥    OR that into hi word
  988.     r5        r5    r0        slw,        ¥    lo word = dvd(lo) << r0
  989. then,
  990.  
  991. ¥ Now for the main restoring division shift and subtract loop.
  992. ¥ With each shift we subtract the divisor from the top half of
  993. ¥  the 128-bit "register", but only use the result if it's positive.
  994. ¥ In this case we shift in a 1 into the low bit position.  Otherwise
  995. ¥  we shift in a 0.  This will be the next bit of the quotient.
  996. ¥ At the end of the loop, we'll have the remainder in the high
  997. ¥  half, and the quotient in the low half.
  998.  
  999.     r10        -1            li,            ¥ r10 = -1 for carry setting
  1000.     r8        r8    0        addic,        ¥ clear carry initially
  1001.  
  1002. CDPx                                    ¥ loop start
  1003.     r5        r5    r5        adde,        ¥ here we shift the long register
  1004.     r6        r6    r6        adde,        ¥  left one place by adding each
  1005.     r7        r7    r7        adde,        ¥  portion to itself, with carry
  1006.     r8        r8    r8        adde,
  1007.     r0        r3    r7        subfc,        ¥ Subtract divisor from hi half
  1008.     r9        r4    r8        subfe.,        ¥  of long register -> r9:r0
  1009.  ge if,                                ¥ Result was positive, so we use it
  1010.     r7        r0            mr,            ¥ move result to hi half of long reg
  1011.     r8        r9            mr,
  1012.     r0        r10    1        addic,        ¥ and set carry bit -
  1013.  then,                                ¥ carry bit will come into the lo
  1014.                                      ¥  bit position of the long reg on
  1015.                                      ¥  the next shift.
  1016.  
  1017. dnz bc,                                ¥ loop
  1018.  
  1019. ¥ now we write the results.  The quotient is in the lo half of the long
  1020. ¥  reg, but needs one more shift, bringing the carry into the lo bit.
  1021. ¥ At the same time we get the quotient to r4:r3, where we want it.
  1022.  
  1023.     r3        r5    r5        adde,        
  1024.     r4        r6    r6        adde,
  1025.  
  1026. ¥ The remainder is in r8:r7 - we now put it back into the memory part
  1027. ¥  of the stack, where the original dividend came from.  As we always
  1028. ¥  return 2 cells in registers from a code definition, we'll now
  1029. ¥  have the remainder under the quotient, as required.
  1030.  
  1031.     r7        4    rSP        stw,
  1032.     r8        0    rSP        stw,
  1033.  
  1034.                         blr,
  1035. then,
  1036.  
  1037. ¥ if we got here, the divisor > dividend, so the quotient is zero
  1038. ¥  and remainder = dividend.  The remainder is already in the right
  1039. ¥  place so we only have to clear the quotient (r4:r3).
  1040.  
  1041.     r3        0            li,
  1042.     r4        0            li,
  1043.                         blr,
  1044.  
  1045. then,
  1046.  
  1047. ¥ and if we got here, the divisor was zero.  We THROW the code -10, which
  1048. ¥  means "division by zero".
  1049.  
  1050.     r4        -10            li,
  1051.     r0        ' throw 2+    dicaddr,
  1052.     r0                    mtctr,
  1053.                         bctr,
  1054. ;ppc_code
  1055.  
  1056.  
  1057. : UM/MOD  ( d u -- urem uquot )
  1058.     0  ud/mod  drop nip  ;
  1059.  
  1060.  
  1061. : UMD/MOD  ( ud_dvd u_dsr -- u_rem ud_quot )
  1062.     0  ud/mod  rot drop  ;
  1063.  
  1064.  
  1065. : M/MOD  ( d n ) { ¥ dvdSgn dsrSgn -- rem quot }
  1066.     false -> dvdSgn
  1067.     s>d  dup -> dsrSgn  tuck + xor
  1068.     over 0< IF  down dnegate rot  true -> dvdSgn  THEN
  1069.     um/mod
  1070.  
  1071. ¥ now we set the sign of the quotient - negative if the
  1072. ¥  signs of the dividend and divisor differed.
  1073.  
  1074.     dvdSgn dsrSgn xor tuck + xor
  1075.  
  1076. ¥ now we set the sign of the remainder - same as dividend.
  1077.  
  1078.     swap dvdSgn tuck + xor  swap
  1079. ;
  1080.  
  1081.  
  1082. : */MOD        inline{ -> rY m* rY m/mod}  ;
  1083.  
  1084. : */        inline{ */mod nip}  ;
  1085.  
  1086.